using System;
using System.IO;

namespace kerberosLibs
{
	/// <summary>
	/// Runs rsync between a local and remote directory.
	/// Uses the special kerberized ssh to effect this!
	/// </summary>
	public class TaskRSync : LoggingConnectionTask
	{
		public TaskRSync()
		{
		}

		private string _remote_machine;
		private string _remote_path;
		private string _local_path;
		private string _remote_username;
		private bool _verbose = false;
		private bool _downloading = true;
		private bool _update = true;

		/// <summary>
		/// Get/Set the Remote Machine to rsync with.
		/// </summary>
		public string RemoteMachine
		{
			get {return _remote_machine;}
			set {_remote_machine = value;}
		}

		/// <summary>
		/// Get/Set the path to find those files on the remote machine.
		/// Relative to users login dir.
		/// </summary>
		public string RemotePath
		{
			get {return _remote_path;}
			set {_remote_path = value;}
		}

		/// <summary>
		/// Get/Set the local path to rsync with.
		/// </summary>
		public string LocalPath
		{
			get {return _local_path;}
			set {_local_path = value;}
		}

		/// <summary>
		/// Get/Set the username to use when contacting the remote folks!
		/// </summary>
		public string RemoteUsername
		{
			get {return _remote_username;}
			set {_remote_username = value;}
		}

		/// <summary>
		/// True if we should be giving lots of feedback.
		/// </summary>
		public bool Verbose
		{
			get {return _verbose;}
			set {_verbose = value;}
		}

		/// <summary>
		/// Get/Set: true if we are going to download, false if we are to upload.
		/// </summary>
		public bool Download
		{
			get {return _downloading;}
			set {_downloading = value;}
		}

		/// <summary>
		/// Get/Set will cause files to be overwritten instead of left alone.
		/// </summary>
		public bool UpdateFilesOnly
		{
			get {return _update;}
			set {_update = value;}
		}

		/// <summary>
		/// The number of steps we have to be involved in!
		/// </summary>
		public override int NumberOfSteps
		{
			get
			{
				return 3;
			}
		}

		/// <summary>
		/// Get this thing off the ground!
		/// </summary>
		public override void Start()
		{
			OnUIStatusUpdate (0, "Starting rsync");

			///
			/// Have to translate the local path into something that good old cygwin can understand.
			/// 

			string t_local_path = _local_path.Replace (@"\", "/");
			t_local_path = t_local_path.Replace (":", "");
			t_local_path = "/cygdrive/" + t_local_path;

			///
			/// If the local path is a directoy, we have to make sure that everyone ends in "/". This
			/// isn't strictly kosher, but if we don't do this, funny and non-obvious things happen. If
			/// an advanced user comaplins about this auto-fixup, then, well, they can add a new option
			/// to the program! :-)
			/// 

			if (System.IO.Directory.Exists (_local_path)) 
			{
				if (!t_local_path.EndsWith("/")) 
				{
					t_local_path += "/";
				}
				if (!_remote_path.EndsWith("/")) 
				{
					_remote_path += "/";
				}
			}

			///
			/// Build arguments for process, and initalize it
			///

			System.Text.StringBuilder bldargs = new System.Text.StringBuilder ();
			if (_downloading) 
			{
				bldargs.AppendFormat ("--rsh=./ssh -lt {5} --recursive {4} {1}@{2}:{3} '{0}'",
					new object[6] {t_local_path,
									  _remote_username,
									  _remote_machine,
									  _remote_path,
									  _verbose ? "-v " : "",
									  _update ? "--update " : ""});
			} 
			else 
			{
				bldargs.AppendFormat ("--rsh=ssh -lt {5} --recursive {4} '{0}' {1}@{2}:{3}",
					new object[6] {t_local_path,
									  _remote_username,
									  _remote_machine,
									  _remote_path,
									  _verbose ? "-v " : "",
									  _update ? "--update " : ""});
			}
			InitProcess (new FileInfo(kerberosLibs.kerberosProductAccess.RSyncPath), bldargs.ToString());
			_proc.OnProcessExit += new kerberosLibs.ProcessWatcher.ProcessExit(_proc_OnProcessExit);

			///
			/// We have to make sure that our specal SSH is found
			/// 

			System.IO.FileInfo fin = kerberosLibs.kerberosProductAccess.SSHPath;
			_proc.AddToPath (fin.DirectoryName);
			_proc.WorkingDirectory = fin.DirectoryName;

			///
			/// Ok -- we are ready to charge off to the races!
			/// 

			StartProcess();
			OnUIStatusUpdate (1, "RSync running");
		}

		/// <summary>
		/// Done!
		/// </summary>
		private void _proc_OnProcessExit()
		{
			OnUIStatusUpdate (2, "RSync done");
			OnTaskDone ();
		}
	}
}
